
import { ClientConnection, gameConnMgr, gameServer } from "./server";
import { ConnectionCollection } from "./ConnectionCollection";
import { MsgSyncFrame } from "./shared/gameClient/protocols/MsgSyncFrame";
import { MsgInpFrame } from "./shared/gameClient/protocols/MsgInpFrame";
import { MsgAfterFrames } from "./shared/gameClient/protocols/MsgAfterFrames";
import { GameMsgCall } from "./api/base";
import { MsgSyncState } from "./shared/gameClient/protocols/MsgSyncState";
import { ConnectionStatus } from "tsrpc";
import { FrameSyncExecutor } from "./FrameSyncExecutor";


export class Game extends ConnectionCollection {

    //private eventEmitter: EventEmitter = new EventEmitter();

    private _inGaming = false;
    /**是否已经开始了游戏*/
    get inGaming() {
        return this._inGaming;
    }

    /**是否启用帧同步功能*/
    public useFrameSync = true;

    /**帧同步执行器*/
    private frameSyncExecutor: FrameSyncExecutor;

    /** [开启useFrameSync] 是否启用随机要求客户端同步状态给服务端的功能,方便大大缩短追帧时间, 随机选一个连着的客户端要求发送*/
    public useRandomRequireConnSync = true;
    private _inRandomRequireConnSyncState: boolean = false;
    /**当前是否在随机要求连接同步游戏状态数据到服务端*/
    get inRandomRequireConnSyncState() {
        return this._inRandomRequireConnSyncState;
    }
    /**随机要求连接同步游戏状态数据到服务端的 定时器句柄*/
    private randomRequireConnSyncStateHD!: NodeJS.Timeout;
    /**随机要求连接同步游戏状态数据到服务端的 定时间隔*/
    public randomRequireConnSyncStateInvMs = 20000;
    private randomRequireConnSyncStateListenHD: Function | undefined;
    /**当前要求同步状态的连接ID,即不是所有客户端发来的同步状态都使用的*/
    private requireSyncStateConnId: string | undefined;

    /**
     * 构造函数
     * @param [syncFrameRate] 同步帧率(每秒多少帧),默认每秒60帧
     */
    constructor(syncFrameRate = 60) {
        super();
        this.frameSyncExecutor = new FrameSyncExecutor((msg) => this.syncOneFrame(msg), syncFrameRate);
        gameConnMgr.onConnAuthed((conn, reconnectId) => {
            //连接加入游戏管理
            this.addConnection(conn);
        });
        gameConnMgr.onConnDiconnect((connId, userInfo) => {
            //不管是否等待重连,都移除,新的或者重连了再加上新的,对于连接来说都是新的, 而这里不管用户为单位,所以可以直接移除
            this.removeConnection(connId);
            return true;
        });
        gameServer.listenMsg('InpFrame', (call: GameMsgCall<MsgInpFrame>) => {
            this.frameSyncExecutor.addConnectionInpFrame(call.conn.connectionId, call.msg);
        });
    }

    private syncOneFrame(msg: MsgSyncFrame) {
        //如果当前没有连接,就不需要广播
        if (this.connections.length <= 0) return;
        //广播给游戏中所有连接
        gameServer.broadcastMsg("SyncFrame", msg, this.connections);
    }

    /**
     * 给连接发追帧数据(最后状态数据+追帧包)
     * @param connectionId 
     */
    public connectionAfterFrames(conn: ClientConnection): void {
        var msg = this.frameSyncExecutor.buildAfterFramesMsg();
        conn.sendMsg("AfterFrames", msg);
    }

    /**
     * 同步游戏状态数据
     * @param stateData 
     * @param stateFrameIndex 
     */
    public syncStateData(stateData: any, stateFrameIndex: number): void {
        this.frameSyncExecutor.syncStateData(stateData, stateFrameIndex);
    }

    /**
     * 添加连接的输入帧到下一帧
     * @param connectionId 
     * @param inpFrame 
     */
    public addConnectionInpFrame(connectionId: string, inpFrame: MsgInpFrame): void {
        this.frameSyncExecutor.addConnectionInpFrame(connectionId, inpFrame);
    }




    /**销毁游戏数据,方便快速回收*/
    public dispose(): void {
        this.stopGame();
    }

    /**
     * 停止随机要求连接同步游戏状态数据给服务端
     */
    public stopRandomRequireConnSyncState(): void {
        this._inRandomRequireConnSyncState = false;
        clearInterval(this.randomRequireConnSyncStateHD);
        if (this.randomRequireConnSyncStateListenHD) {
            gameServer.unlistenMsg('SyncState', this.randomRequireConnSyncStateListenHD);
        }
    }
    /**
     * 开始随机要求连接同步游戏状态数据给服务端
     */
    public startRandomRequireConnSyncState(): void {
        this.stopRandomRequireConnSyncState();
        this.randomRequireConnSyncStateListenHD = gameServer.listenMsg("SyncState", (call: GameMsgCall<MsgSyncState>) => {
            //必须是服务端当前指定的(信任的),否则不使用这同步数据
            if (this.requireSyncStateConnId != call.conn.connectionId) return;
            //同步服务端状态数据
            this.frameSyncExecutor.syncStateData(call.msg.stateData, call.msg.stateFrameIndex);
        });
        this.randomRequireConnSyncStateHD = setInterval(this.onRandomRequireConnSyncState.bind(this), this.randomRequireConnSyncStateInvMs);
        this._inRandomRequireConnSyncState = false;
    }
    /**
     * 处理随机要求连接同步游戏状态数据给服务端
     */
    onRandomRequireConnSyncState(): void {
        //如果当前没有连接,直接返回
        if (this.connections.length <= 0) return;

        var conn: ClientConnection | undefined;
        if (this.requireSyncStateConnId) {
            //已经指定过连接了,直接获取
            conn = this.connectionMap.get(this.requireSyncStateConnId);
        }
        if (!conn || conn.status != ConnectionStatus.Opened) {
            //没指定过或者之前指定的不能用了,则重新随机一个
            var connIndex = Math.floor(Math.random() * this.connections.length);
            conn = this.connections[connIndex];
            this.requireSyncStateConnId = conn.connectionId;
        }

        conn.sendMsg("RequireSyncState", {});
    }


    /**开始游戏,根据启用的功能,直接开始游戏服务支持*/
    public startGame(): void {
        if (this.useFrameSync) {
            this.frameSyncExecutor.startSyncFrame();
            if (this.useRandomRequireConnSync) {
                this.startRandomRequireConnSyncState();
            }
        }
        this._inGaming = true;
    }
    /**停止游戏内相关功能,并回收或重置相关数据*/
    public stopGame(): void {
        this._inGaming = false;
        if (this.useFrameSync) {
            this.frameSyncExecutor.stopSyncFrame();
        }
        this.stopRandomRequireConnSyncState();
        this.clearAllConnections();
    }

}